package com.sherlocky.learning.java17.sealed.classes;

/**
 * Sealed修饰符
 * 作用域：类、抽象类、接口。不可作用域内部类上
 * 目标：声明一个类或为密封类，只有指定的类才可以继承改类。
 *      声明一个接口为密封接口，只有指定的接口可以继承该接口，只有指定的类可以实现该接口。
 *
 * JDK 中的 sealed 使用案例：{@link java.lang.constant.ConstantDesc}
 *
 * {@link java.lang.Class} 添加了两个关于sealed的API
 *    1. Class<?>[] {@link Class#getPermittedSubclasses}
 *        1.1 返回一个包含Class对象的数组，这些对象表示允许扩展或实现此类或接口（如果它是密封的）的直接子接口或子类。(顺序未指定)
 *        1.2 如果此密封类或接口没有允许的子类，则数组为空。
 *        1.3 如果此Class对象表示原始类型、void、数组类型或未密封的类或接口，即isSealed()返回false ，则此方法返回null。
 *    2. boolean {@link Class#isSealed}
 *
 * @date: 2021/9/20 23:06
 * @since:
 */
public abstract sealed class Shape
        permits Circle, Rectangle, Square, WeirdShape {

    /**
     1.密封类及其允许的子类必须属于同一个模块，并且如果在未命名的模块中声明，则属于同一个包
     2.每个允许的子类必须为final、sealed，或non-sealed。
     3.每个允许的子类必须使用修饰符来描述它如何传播由其超类发起的密封：
        3.1 可以声明允许的子类final以防止其在类层次结构中的部分被进一步扩展。
            （<a href="https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-8.10">Record classes</a>是隐式声明的final。）
        3.2 一个允许的子类可以被声明为 sealed, 允许它的层次结构部分比其密封超类所设想的更进一步，但以一种受限的方式。
        3.3 可以声明一个允许的子类，non-sealed以便它的层次结构部分恢复为对未知子类的扩展开放。
        密封类不能阻止其允许的子类这样做。
        （修饰符non-sealed是 为 Java 提议的第一个带连字符的关键字。）
     */
}

final class Circle extends Shape {

}

sealed class Rectangle extends Shape
        permits TransparentRectangle, FilledRectangle {

}
final class TransparentRectangle extends Rectangle {

}

final class FilledRectangle extends Rectangle {

}

final class Square extends Shape {

}

non-sealed class WeirdShape extends Shape {

}

class AnyWeirdShape extends WeirdShape {

}